gsk: Add gsk_render_node_draw()
authorBenjamin Otte <otte@redhat.com>
Tue, 13 Dec 2016 02:05:15 +0000 (03:05 +0100)
committerBenjamin Otte <otte@redhat.com>
Tue, 20 Dec 2016 17:01:10 +0000 (18:01 +0100)
Draws a node to a given cairo_t. This is mostly intended for fallback
usage.

docs/reference/gsk/gsk4-sections.txt
gsk/gskcairorenderer.c
gsk/gskrendernode.c
gsk/gskrendernode.h
gsk/gskrendernodeimpl.c
gsk/gskrendernodeprivate.h

index 4bbeba513a4759834693baeb734fbf67a0a7f32a..8e6239d427a66ef3233afcb526f6d0994d29b9c0 100644 (file)
@@ -28,6 +28,7 @@ gsk_render_node_ref
 gsk_render_node_unref
 GskRenderNodeType
 gsk_render_node_get_node_type
+gsk_render_node_draw
 gsk_render_node_set_opacity
 GskBlendMode
 gsk_render_node_set_blend_mode
index 4fd85927d90fbd345e433a9528c6a29db62b9d29..3fb394a5de62f8575e874be3ac5a87f239700e4a 100644 (file)
@@ -46,121 +46,6 @@ gsk_cairo_renderer_unrealize (GskRenderer *renderer)
 
 }
 
-static void
-gsk_cairo_renderer_render_node (GskCairoRenderer *self,
-                                GskRenderNode    *node,
-                                cairo_t          *cr)
-{
-  gboolean pop_group = FALSE;
-  graphene_rect_t frame;
-
-  cairo_save (cr);
-
-  gsk_render_node_get_bounds (node, &frame);
-  GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
-                            frame.origin.x, frame.origin.y,
-                            frame.size.width, frame.size.height));
-
-  if (!GSK_RENDER_MODE_CHECK (GEOMETRY))
-    {
-      cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
-      cairo_clip (cr);
-    }
-
-  if (gsk_render_node_get_opacity (node) != 1.0)
-    {
-      GSK_NOTE (CAIRO, g_print ("Pushing opacity group (opacity:%g)\n",
-                                gsk_render_node_get_opacity (node)));
-      cairo_push_group (cr);
-      pop_group = TRUE;
-    }
-
-  GSK_NOTE (CAIRO, g_print ("Rendering node %s[%p] at %g, %g\n",
-                            node->name,
-                            node,
-                            frame.origin.x, frame.origin.y));
-
-  switch (gsk_render_node_get_node_type (node))
-    {
-    case GSK_NOT_A_RENDER_NODE:
-    default:
-      g_assert_not_reached ();
-      break;
-
-    case GSK_CONTAINER_NODE:
-      {
-        guint i;
-        GSK_NOTE (CAIRO, g_print ("Drawing %d children of node [%p]\n",
-                                  gsk_container_node_get_n_children (node),
-                                  node));
-        for (i = 0; i < gsk_container_node_get_n_children (node); i++)
-          {
-            gsk_cairo_renderer_render_node (self, gsk_container_node_get_child (node, i), cr);
-          }
-      }
-      break;
-
-    case GSK_TEXTURE_NODE:
-      {
-        GskTexture *texture = gsk_texture_node_get_texture (node);
-        cairo_surface_t *surface = gsk_texture_download (texture);
-
-        cairo_set_source_surface (cr, surface, frame.origin.x, frame.origin.y); 
-        cairo_paint (cr);
-        cairo_surface_destroy (surface);
-      }
-      break;
-
-    case GSK_CAIRO_NODE:
-      {
-        cairo_set_source_surface (cr, gsk_cairo_node_get_surface (node), frame.origin.x, frame.origin.y); 
-        cairo_paint (cr);
-      }
-      break;
-
-    case GSK_TRANSFORM_NODE:
-      {
-        graphene_matrix_t mat;
-        cairo_matrix_t ctm;
-
-        gsk_transform_node_get_transform (node, &mat);
-        if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
-          {
-            GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
-                                      ctm.xx, ctm.yx,
-                                      ctm.xy, ctm.yy,
-                                      ctm.x0, ctm.y0));
-            cairo_transform (cr, &ctm);
-          }
-        else
-          g_critical ("Invalid non-affine transformation for node %p", node);
-
-        gsk_cairo_renderer_render_node (self, gsk_transform_node_get_child (node), cr);
-      }
-      break;
-    }
-
-  if (GSK_RENDER_MODE_CHECK (GEOMETRY))
-    {
-      cairo_save (cr);
-      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-      cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2);
-      cairo_set_line_width (cr, 2);
-      cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
-      cairo_stroke (cr);
-      cairo_restore (cr);
-    }
-
-  if (pop_group)
-    {
-      cairo_pop_group_to_source (cr);
-      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-      cairo_paint_with_alpha (cr, gsk_render_node_get_opacity (node));
-    }
-
-  cairo_restore (cr);
-}
-
 static void
 gsk_cairo_renderer_render (GskRenderer   *renderer,
                            GskRenderNode *root)
@@ -209,7 +94,7 @@ gsk_cairo_renderer_render (GskRenderer   *renderer,
   gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
 #endif
 
-  gsk_cairo_renderer_render_node (self, root, cr);
+  gsk_render_node_draw (root, cr);
 
 #ifdef G_ENABLE_DEBUG
   cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
index 5b53c9197fc7b0958ad32755db673ad8bd721244..1a343ae852a69acc11aa1361045c7b7592005c5c 100644 (file)
@@ -335,3 +335,62 @@ gsk_render_node_make_immutable (GskRenderNode *node)
   node->is_mutable = FALSE;
 }
 
+/**
+ * gsk_render_node_draw:
+ * @node: a #GskRenderNode
+ * @cr: cairo context to draw to
+ *
+ * Draw the contents of @node to the given cairo context.
+ *
+ * Typically, you'll use this function to implement fallback rendering
+ * of #GskRenderNodes on an intermediate Cairo context, instead of using
+ * the drawing context associated to a #GdkWindow's rendering buffer.
+ *
+ * For advanced nodes that cannot be supported using Cairo, in particular
+ * for nodes doing 3D operations, this function may fail.
+ **/
+void
+gsk_render_node_draw (GskRenderNode *node,
+                      cairo_t       *cr)
+{
+  g_return_if_fail (GSK_IS_RENDER_NODE (node));
+  g_return_if_fail (cr != NULL);
+
+  cairo_save (cr);
+
+  if (!GSK_RENDER_MODE_CHECK (GEOMETRY))
+    {
+      graphene_rect_t frame;
+
+      gsk_render_node_get_bounds (node, &frame);
+      GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
+                                frame.origin.x, frame.origin.y,
+                                frame.size.width, frame.size.height));
+
+      cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+      cairo_clip (cr);
+    }
+
+  GSK_NOTE (CAIRO, g_print ("Rendering node %s[%p]\n",
+                            node->name,
+                            node));
+
+  node->node_class->draw (node, cr);
+
+  if (GSK_RENDER_MODE_CHECK (GEOMETRY))
+    {
+      graphene_rect_t frame;
+
+      gsk_render_node_get_bounds (node, &frame);
+
+      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+      cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2);
+      cairo_set_line_width (cr, 2);
+      cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
+      cairo_stroke (cr);
+    }
+
+  cairo_restore (cr);
+}
+
+
index 93a100eaf64bc94f9d1a9cc8041c73249adb9c0e..c874cb5b2e84ff88b45f5cfe24a010bef88788b0 100644 (file)
@@ -88,6 +88,9 @@ void                    gsk_render_node_set_name                (GskRenderNode *
 GDK_AVAILABLE_IN_3_90
 const char *            gsk_render_node_get_name                (GskRenderNode *node);
 
+GDK_AVAILABLE_IN_3_90
+void                    gsk_render_node_draw                    (GskRenderNode *node,
+                                                                 cairo_t       *cr);
 G_END_DECLS
 
 #endif /* __GSK_RENDER_NODE_H__ */
index d23d18ddbac5d60f2e272f3773466034b048a026..b80c0f6aeeb282dcb25bb4c8c93251768afd986d 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "gskdebugprivate.h"
 #include "gskrendererprivate.h"
-#include "gsktexture.h"
+#include "gsktextureprivate.h"
 
 /*** GSK_TEXTURE_NODE ***/
 
@@ -47,6 +47,30 @@ gsk_texture_node_make_immutable (GskRenderNode *node)
 {
 }
 
+static void
+gsk_texture_node_draw (GskRenderNode *node,
+                       cairo_t       *cr)
+{
+  GskTextureNode *self = (GskTextureNode *) node;
+  cairo_surface_t *surface;
+
+  surface = gsk_texture_download (self->texture);
+
+  cairo_save (cr);
+
+  cairo_translate (cr, self->bounds.origin.x, self->bounds.origin.y);
+  cairo_scale (cr,
+               self->bounds.size.width / gsk_texture_get_width (self->texture),
+               self->bounds.size.height / gsk_texture_get_height (self->texture));
+
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_paint (cr);
+
+  cairo_restore (cr);
+
+  cairo_surface_destroy (surface);
+}
+
 static void
 gsk_texture_node_get_bounds (GskRenderNode   *node,
                              graphene_rect_t *bounds)
@@ -62,6 +86,7 @@ static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = {
   "GskTextureNode",
   gsk_texture_node_finalize,
   gsk_texture_node_make_immutable,
+  gsk_texture_node_draw,
   gsk_texture_node_get_bounds
 };
 
@@ -130,6 +155,19 @@ gsk_cairo_node_make_immutable (GskRenderNode *node)
 {
 }
 
+static void
+gsk_cairo_node_draw (GskRenderNode *node,
+                     cairo_t       *cr)
+{
+  GskCairoNode *self = (GskCairoNode *) node;
+
+  if (self->surface == NULL)
+    return;
+
+  cairo_set_source_surface (cr, self->surface, self->bounds.origin.x, self->bounds.origin.y);
+  cairo_paint (cr);
+}
+
 static void
 gsk_cairo_node_get_bounds (GskRenderNode   *node,
                            graphene_rect_t *bounds)
@@ -145,6 +183,7 @@ static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = {
   "GskCairoNode",
   gsk_cairo_node_finalize,
   gsk_cairo_node_make_immutable,
+  gsk_cairo_node_draw,
   gsk_cairo_node_get_bounds
 };
 
@@ -313,6 +352,19 @@ gsk_container_node_make_immutable (GskRenderNode *node)
     }
 }
 
+static void
+gsk_container_node_draw (GskRenderNode *node,
+                         cairo_t       *cr)
+{
+  GskContainerNode *container = (GskContainerNode *) node;
+  guint i;
+
+  for (i = 0; i < container->n_children; i++)
+    {
+      gsk_render_node_draw (container->children[i], cr);
+    }
+}
+
 static void
 gsk_container_node_get_bounds (GskRenderNode   *node,
                                graphene_rect_t *bounds)
@@ -343,6 +395,7 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
   "GskContainerNode",
   gsk_container_node_finalize,
   gsk_container_node_make_immutable,
+  gsk_container_node_draw,
   gsk_container_node_get_bounds
 };
 
@@ -436,9 +489,38 @@ gsk_transform_node_make_immutable (GskRenderNode *node)
   gsk_render_node_make_immutable (self->child);
 }
 
+static void
+gsk_transform_node_draw (GskRenderNode *node,
+                         cairo_t       *cr)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+  cairo_matrix_t ctm;
+
+  if (graphene_matrix_to_2d (&self->transform, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
+    {
+      GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
+                                ctm.xx, ctm.yx,
+                                ctm.xy, ctm.yy,
+                                ctm.x0, ctm.y0));
+      cairo_transform (cr, &ctm);
+  
+      gsk_render_node_draw (self->child, cr);
+    }
+  else
+    {
+      graphene_rect_t bounds;
+
+      gsk_render_node_get_bounds (node, &bounds);
+
+      cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.);
+      cairo_rectangle (cr, bounds.origin.x, bounds.origin.x, bounds.size.width, bounds.size.height);
+      cairo_fill (cr);
+    }
+}
+
 static void
 gsk_transform_node_get_bounds (GskRenderNode   *node,
-                           graphene_rect_t *bounds)
+                               graphene_rect_t *bounds)
 {
   GskTransformNode *self = (GskTransformNode *) node;
   graphene_rect_t child_bounds;
@@ -456,6 +538,7 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
   "GskTransformNode",
   gsk_transform_node_finalize,
   gsk_transform_node_make_immutable,
+  gsk_transform_node_draw,
   gsk_transform_node_get_bounds
 };
 
index 85117f4aa78b92625d0ab7584d92162448c904cf..239e64dc70719d703f4b855a9028bf88e1b164a4 100644 (file)
@@ -40,6 +40,8 @@ struct _GskRenderNodeClass
   const char *type_name;
   void (* finalize) (GskRenderNode *node);
   void (* make_immutable) (GskRenderNode *node);
+  void (* draw) (GskRenderNode *node,
+                 cairo_t       *cr);
   void (* get_bounds) (GskRenderNode   *node,
                        graphene_rect_t *bounds);
 };